#include "sk_b2_properties_helper.h"

#ifndef SK_GAME_PROJECT
    #include "sk_game_item_property.h"
#endif

#include <Box2D/Dynamics/b2Body.h>
#include <Box2D/Dynamics/b2Fixture.h>

#include <QDebug>
#include <QDomDocument>
#include <QDomElement>

namespace sk
{



void B2PropertiesHelper::serialize(QDomDocument * doc, QDomElement * parent, b2BodyDef * def)
{
    QDomElement bodyElement = doc->createElement("b2BodyDef");
    bodyElement.setAttribute("position.x", def->position.x);
    bodyElement.setAttribute("position.y", def->position.y);
    bodyElement.setAttribute("angle", def->angle);
    bodyElement.setAttribute("linearVelocity.x", def->linearVelocity.x);
    bodyElement.setAttribute("linearVelocity.y", def->linearVelocity.y);
    bodyElement.setAttribute("angularVelocity", def->angularVelocity);
    bodyElement.setAttribute("linearDamping", def->linearDamping);
    bodyElement.setAttribute("angularDamping", def->angularDamping);
    bodyElement.setAttribute("allowSleep", def->allowSleep);
    bodyElement.setAttribute("awake", def->awake);
    bodyElement.setAttribute("fixedRotation", def->fixedRotation);
    bodyElement.setAttribute("bullet", def->bullet);
    bodyElement.setAttribute("type", (int)def->type);
    bodyElement.setAttribute("active", def->active);
    bodyElement.setAttribute("inertiaScale", def->inertiaScale);
    parent->appendChild(bodyElement);
}

bool B2PropertiesHelper::deserialize(QDomElement * parent, b2BodyDef * def)
{
    for (int i = 0; i < parent->childNodes().count(); ++i)
    {
        QDomElement e = parent->childNodes().at(i).toElement();
        if (e.tagName() == "b2BodyDef")
        {
            def->position.x = e.attribute("position.x").toFloat();
            def->position.y = e.attribute("position.y").toFloat();
            def->angle = e.attribute("angle").toFloat();
            def->linearVelocity.x = e.attribute("linearVelocity.x").toFloat();
            def->linearVelocity.y = e.attribute("linearVelocity.y").toFloat();
            def->angularVelocity = e.attribute("angularVelocity").toFloat();
            def->linearDamping = e.attribute("linearDamping").toFloat();
            def->angularDamping = e.attribute("angularDamping").toFloat();
            def->allowSleep = e.attribute("allowSleep") == "1";
            def->awake = e.attribute("awake") == "1";
            def->fixedRotation = e.attribute("fixedRotation") == "1";
            def->bullet = e.attribute("bullet") == "1";
            def->type = (b2BodyType)e.attribute("type").toInt();
            def->active = e.attribute("active") == "1";
            def->inertiaScale = e.attribute("inertiaScale").toFloat();
            return true;
        }
    }
    return false;
}

#ifndef SK_GAME_PROJECT

int B2PropertiesHelper::numBodyDefProperties()
{
    return 15;
}

GameItemProperty * B2PropertiesHelper::bodyDefProperty(GameItem * item, int ind, b2BodyDef * def)
{
    Q_ASSERT(ind >= 0 && ind < numBodyDefProperties());
    if (0 == ind)
    {
        return new GameItemFloatProperty(item, "position.x", &def->position.x);
    }
    if (1 == ind)
    {
        return new GameItemFloatProperty(item, "position.y", &def->position.y);
    }
    if (2 == ind)
    {
        return new GameItemFloatProperty(item, "angle", &def->angle);
    }
    if (3 == ind)
    {
        return new GameItemFloatProperty(item, "linearVelocity.x", &def->linearVelocity.x);
    }
    if (4 == ind)
    {
        return new GameItemFloatProperty(item, "linearVelocity.y", &def->linearVelocity.y);
    }
    if (5 == ind)
    {
        return new GameItemFloatProperty(item, "angularVelocity", &def->angularVelocity);
    }
    if (6 == ind)
    {
        return new GameItemFloatProperty(item, "linearDamping", &def->linearDamping);
    }
    if (7 == ind)
    {
        return new GameItemFloatProperty(item, "angularDamping", &def->angularDamping);
    }
    if (8 == ind)
    {
        return new GameItemBoolProperty(item, "allowSleep", &def->allowSleep);
    }
    if (9 == ind)
    {
        return new GameItemBoolProperty(item, "awake", &def->awake);
    }
    if (10 == ind)
    {
        return new GameItemBoolProperty(item, "fixedRotation", &def->fixedRotation);
    }
    if (11 == ind)
    {
        return new GameItemBoolProperty(item, "bullet", &def->bullet);
    }
    if (12 == ind)
    {
        QStringList ns;
        ns << "Static Body" << "Kinematic Body" << "Dynamic Body";
        QVector<int> es;
        es << b2_staticBody << b2_kinematicBody << b2_dynamicBody;
        return new GameItemEnumProperty(item, "type", (int*)&def->type, ns, es);
    }
    if (13 == ind)
    {
        return new GameItemBoolProperty(item, "active", &def->active);
    }
    if (14 == ind)
    {
        return new GameItemFloatProperty(item, "inertiaScale", &def->inertiaScale);
    }
    return 0;
}

/*
filter.categoryBits = 0x0001; NOT SUPPORTED
filter.maskBits = 0xFFFF;     NOT SUPPORTED
filter.groupIndex = 0;        NOT SUPPORTED
*/

int B2PropertiesHelper::numFixtureDefProperties()
{
    return 7;
}

GameItemProperty * B2PropertiesHelper::fixtureDefProperty(GameItem * item, int ind, b2FixtureDef * def)
{
    Q_ASSERT(ind >= 0 && ind < numFixtureDefProperties());
    if (0 == ind)
    {
        return new GameItemFloatProperty(item, "friction", &def->friction);
    }
    if (1 == ind)
    {
        return new GameItemFloatProperty(item, "restitution", &def->restitution);
    }
    if (2 == ind)
    {
        return new GameItemFloatProperty(item, "density", &def->density);
    }
    if (3 == ind)
    {
        return new GameItemBoolProperty(item, "isSensor", &def->isSensor);
    }
    if (4 == ind)
    {
        GameItemShortProperty * res = new GameItemShortProperty(item, "filter.categoryBits", (short*)&def->filter.categoryBits);
        return res;
    }
    if (5 == ind)
    {
        GameItemShortProperty * res = new GameItemShortProperty(item, "filter.maskBits", (short*)&def->filter.maskBits);
        return res;
    }
    if (6 == ind)
    {
        GameItemShortProperty * res = new GameItemShortProperty(item, "filter.groupIndex", (short*)&def->filter.groupIndex);
        return res;
    }

    return 0;
}
#endif

void B2PropertiesHelper::serialize(QDomDocument * doc, QDomElement * parent, b2FixtureDef * def)
{
    QDomElement fixtureElement = doc->createElement("b2FixtureDef");
    fixtureElement.setAttribute("friction", def->friction);
    fixtureElement.setAttribute("restitution", def->restitution);
    fixtureElement.setAttribute("density", def->density);
    fixtureElement.setAttribute("isSensor", def->isSensor);
    fixtureElement.setAttribute("filter.categoryBits", def->filter.categoryBits);
    fixtureElement.setAttribute("filter.maskBits", def->filter.maskBits);
    fixtureElement.setAttribute("filter.groupIndex", def->filter.groupIndex);
    parent->appendChild(fixtureElement);
}

bool B2PropertiesHelper::deserialize(QDomElement * parent, b2FixtureDef * def)
{
    for (int i = 0; i < parent->childNodes().count(); ++i)
    {
        QDomElement e = parent->childNodes().at(i).toElement();
        if (e.tagName() == "b2FixtureDef")
        {
            def->friction    = e.attribute("friction").toFloat();
            def->restitution = e.attribute("restitution").toFloat();
            def->density     = e.attribute("density").toFloat();
            def->isSensor    = e.attribute("isSensor") == "1";
            if (e.hasAttribute("filter.categoryBits"))
            {
                def->filter.categoryBits = (uint16)e.attribute("filter.categoryBits").toInt();
            }
            if (e.hasAttribute("filter.maskBits"))
            {
                def->filter.maskBits = (uint16)e.attribute("filter.maskBits").toInt();
            }
            if (e.hasAttribute("filter.groupIndex"))
            {
                def->filter.groupIndex = (int16)e.attribute("filter.groupIndex").toInt();
            }
            return true;
        }
    }
    return false;
}


} // namespace sk

